package org.lundberg.podcasts;

import java.io.File;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;

import org.lundberg.podcasts.types.Channel;
import org.lundberg.podcasts.util.DownloadIconTask;
import org.lundberg.podcasts.util.PodcastDB;
import org.lundberg.podcasts.util.QueueAdapter;
import org.lundberg.podcasts.util.SubscriptionsAdapter;
import org.lundberg.podcasts.util.Util;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Parcelable;
import android.preference.PreferenceManager;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.CursorAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.viewpagerindicator.TitlePageIndicator;
import com.viewpagerindicator.TitleProvider;

public class MainActivity extends Activity
{
	private static final int DOWNLOAD_MENU_ITEM = Menu.FIRST;
	private static final int REMOVE_DOWNLOAD_MENU_ITEM = Menu.FIRST+1;
	private static final int CANCEL_DOWNLOAD_MENU_ITEM = Menu.FIRST+2;
	private static final int MARK_LISTENED_MENU_ITEM = Menu.FIRST+3;
	
	private View refreshView = null;
	private MenuItem refreshMenuItem = null;
	private Animation rotation = null;
	private HashMap<Integer, Bitmap> iconCache = new HashMap<Integer, Bitmap>();
    private ViewPager pager;
    private MyPagerAdapter mAdapter;
    private CursorAdapter sAdapter = null;
    private CursorAdapter qAdapter = null;
    private Channel selectedChannel = null;
    private int currentView = 0;
    private final Handler mUpdateHandler = new Handler();
    private boolean isDownloadServiceBound = false;
	private DownloadService mDownloadService = null;
	private final ServiceConnection mConnection = new ServiceConnection() {
	    @Override
		public void onServiceConnected(ComponentName className, IBinder service) {
	    	mDownloadService = ((DownloadService.LocalBinder)service).getService();
	    }
	    @Override
		public void onServiceDisconnected(ComponentName className) {
	    	mDownloadService = null;
	    }
	};
	private IntentFilter mIntentFilter;
	private BroadcastReceiver mStatusListener = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {

        	Log.d("MainActivity", "onReceive: "+intent.getAction());
        	
        	if (UpdateService.UPDATED.equals(intent.getAction()))
        	{
        		refreshMenuItem.getActionView().clearAnimation();
        	    refreshMenuItem.setActionView(null);
        	    if (intent.getIntExtra("count", 0) > 0) {
        			requery();
        		}
        	}
        	else if (DownloadService.FINISHED_DOWNLOAD.equals(intent.getAction()))
        	{
        		requery();
        	}
        }
	};
	
        
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_layout);
        
        Intent intent = getIntent();
        
        if (intent != null)
        {
	        final Uri data = getIntent().getData();
	    	
	        if (data != null) {
	    		
	    		Log.d("MainActivity", "onCreate - received intent: "+data);
	    		new AddRefreshPodcastsTask(data.toString()).execute();
	    	}
        }
        
        mAdapter = new MyPagerAdapter();
        pager = (ViewPager) findViewById(R.id.awesomepager);
        pager.setAdapter(mAdapter);
        
        TitlePageIndicator indicator = (TitlePageIndicator)findViewById( R.id.indicator );
        indicator.setViewPager(pager);
        
        indicator.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
        	@Override
            public void onPageSelected(int position) {
        		currentView = position;
            }
        });
        
        SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
    	currentView = settings.getInt("current_view", 0);
    	
    	pager.setCurrentItem(currentView);
    }
    
    
    @Override
    public void onResume()
    {
    	super.onResume();
    	
		if (!isDownloadServiceBound) {
		    		
			bindService(new Intent(getApplicationContext(),  DownloadService.class), mConnection, Context.BIND_AUTO_CREATE);
    		isDownloadServiceBound = true;
    	}
		
		if (mIntentFilter == null) {

			mIntentFilter = new IntentFilter();
            mIntentFilter.addAction(UpdateService.UPDATED);
            mIntentFilter.addAction(DownloadService.FINISHED_DOWNLOAD);
        }
		
		
		if (!(sAdapter == null || qAdapter == null)) {
			requery();
		}
		
    	registerReceiver(mStatusListener, mIntentFilter);
    	
    	
    	// set up now_playing_bar
    	SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
    	String guid = settings.getString("current_item_guid", null);
    	
    	if (guid != null)
    	{
    		final ImageView icon = (ImageView) findViewById(R.id.now_playing_icon);
    		TextView title = (TextView) findViewById(R.id.now_playing_title);
    		
    		PodcastDB helper = new PodcastDB(getApplicationContext());
			SQLiteDatabase db = helper.getReadableDatabase();
			Cursor cursor = db.query(false, PodcastDB.ITEMS_TABLE,
									new String[] {"channel_id", "title"},
					        		"guid=?", new String[] {guid}, null, null, null, "1");
			
			if (cursor.moveToFirst()) {
				
				final int channel_id = cursor.getInt(0);
				ViewTreeObserver vto = icon.getViewTreeObserver();
				vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
				    public boolean onPreDraw() {
				    	new PagerActivityDownloadIconTask(channel_id, icon).execute();
				    	icon.getViewTreeObserver().removeOnPreDrawListener(this);
				        return true;
				    }
				});
				
				title.setText(cursor.getString(1));
			}
			
			cursor.close();
			helper.close();
    	}
    	
    	View now_playing_bar = findViewById(R.id.now_playing_bar);
    	now_playing_bar.setVisibility((guid == null) ? View.GONE : View.VISIBLE);
    }
    
    
    
    
    @Override
    public void onPause()
    {
    	super.onPause();
    	
    	unregisterReceiver(mStatusListener);
    	
    	SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
		Editor editor = settings.edit();
		editor.putInt("current_view", currentView);
		editor.commit();
		
		if (sAdapter != null) {
			sAdapter.getCursor().close();
		}
		
		if (qAdapter != null) {
			qAdapter.getCursor().close();
		}
    }
    
    
    @Override
	public void onDestroy()
	{
		super.onDestroy();
		
		if (isDownloadServiceBound) {
    		unbindService(mConnection);
    		isDownloadServiceBound = false;
    	}
	}
    
    
    private class MyPagerAdapter extends PagerAdapter implements TitleProvider
    {
    	private String[] titles = new String[] {"Subscriptions", "Queue"};
    	
    	@Override
    	public String getTitle( int position ) {
    		return titles[ position ];
    	}

    	
        @Override
        public int getCount() {
            return 2;
        }

			/**
			 * Create the page for the given position.  The adapter is responsible
			 * for adding the view to the container given here, although it only
			 * must ensure this is done by the time it returns from
			 * {@link #finishUpdate()}.
			 *
			 * @param container The containing View in which the page will be shown.
			 * @param position The page position to be instantiated.
			 * @return Returns an Object representing the new page.  This does not
			 * need to be a View, but can be some other container of the page.
			 */
            @Override
            public Object instantiateItem(View container, int position)
            {
            	PodcastDB helper = new PodcastDB(getApplicationContext());
    			SQLiteDatabase db = helper.getReadableDatabase();
    			ListView listView = new ListView(getApplicationContext());
    			//listView.setVerticalFadingEdgeEnabled(false);
    			listView.setCacheColorHint(0);
    			
    			if (position == 0) {
    				
    				Cursor cursor = db.query(false, PodcastDB.CHANNELS_TABLE,
    									SubscriptionsAdapter.COLUMNS,
        	                			null, null, null, null, "title", null);
    					
					sAdapter = new SubscriptionsAdapter(MainActivity.this, cursor, iconCache);
					
    				listView.setAdapter(sAdapter);
    			}
    			else {
    				
    				Cursor cursor = db.query(false, PodcastDB.ITEMS_TABLE,
    									QueueAdapter.COLUMNS,
    									"listened = 0", null, null, null, "pubDate", null);
    					
					qAdapter = new QueueAdapter(MainActivity.this, cursor, iconCache);
					
					listView.setAdapter(qAdapter);
    			}
    			
    			helper.close();
    			
    			listView.setOnItemClickListener(new MyClickListener());
    			
    			MainActivity.this.registerForContextMenu(listView);
    			
    			((ViewPager) container).addView(listView, 0);
    			
    			return listView;
            }

	        /**
	         * Remove a page for the given position.  The adapter is responsible
	         * for removing the view from its container, although it only must ensure
	         * this is done by the time it returns from {@link #finishUpdate()}.
	         *
	         * @param container The containing View from which the page will be removed.
	         * @param position The page position to be removed.
	         * @param object The same object that was returned by
	         * {@link #instantiateItem(View, int)}.
	         */
            @Override
            public void destroyItem(View collection, int position, Object view) {
                ((ViewPager) collection).removeView((TextView) view);
            }

            
            
            @Override
            public boolean isViewFromObject(View view, Object object) {
                return view==((ListView)object);
            }

            
	        /**
	         * Called when the a change in the shown pages has been completed.  At this
	         * point you must ensure that all of the pages have actually been added or
	         * removed from the container as appropriate.
	         * @param container The containing View which is displaying this adapter's
	         * page views.
	         */
            @Override
            public void finishUpdate(View arg0) {
            }

            @Override
            public void restoreState(Parcelable arg0, ClassLoader arg1) {}

            @Override
            public Parcelable saveState() {
                return null;
            }

            @Override
            public void startUpdate(View arg0) {}
        
    }
    
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

    	super.onCreateOptionsMenu(menu);
    	
    	MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.subscriptions_menu, menu);
        
        if (refreshMenuItem == null) {
        	refreshMenuItem = menu.findItem(R.id.refresh_menu_item);
        }
        
        return true;
    }
    
    
    
    private class MyClickListener implements AdapterView.OnItemClickListener
    {
		@Override
		public void onItemClick(AdapterView<?> arg0, View view, int position, long id)
		{
			
			if (currentView == 0)
			{
				// open ItemsActivity
				Channel channel = new Channel((Cursor) sAdapter.getItem(position));
				Intent intent = new Intent(MainActivity.this, ItemsActivity.class);
				intent.putExtra("channel", channel);
				startActivity(intent);
			}
			else if (currentView == 1)
			{
				// Open PlayerActivity
				Intent intent = new Intent(MainActivity.this, PlayerActivity.class);
		    	intent.putExtra("guid", qAdapter.getCursor().getString(0));
		    	intent.putExtra("queue_type", "Queue");
		    	startActivity(intent);
			}
		}
    }
    
    
    @Override
	public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)
	{
    	if (currentView == 0)
    	{
			super.onCreateContextMenu(menu, v, menuInfo);
			MenuInflater inflater = getMenuInflater();
			inflater.inflate(R.menu.subscriptions_context_menu, menu);
    	}
    	else if (currentView == 1)
    	{
    		menu.add(0, MARK_LISTENED_MENU_ITEM, Menu.NONE, "Mark as listened");
    	    
    	    String guid = qAdapter.getCursor().getString(0);
    	    
    	    if (mDownloadService.isDownloading(guid)) {
        		
        		menu.add(0, CANCEL_DOWNLOAD_MENU_ITEM, Menu.NONE, "Cancel download");
        	}
    	    else if (Util.isDownloaded(qAdapter.getCursor().getString(0))) {
        		
        		menu.add(0, REMOVE_DOWNLOAD_MENU_ITEM, Menu.NONE, "Remove download");
        	}
        	else {
        	
        		menu.add(0, DOWNLOAD_MENU_ITEM, Menu.NONE, "Download");
        	}
    	}
	}
    
    
    
    @Override
	public boolean onMenuItemSelected(int featureId, MenuItem menuItem)
    {
		// Get the info on which item was selected
    	CursorAdapter adapter = (currentView == 0) ? sAdapter : qAdapter;
	    
	    switch (menuItem.getItemId())
    	{
		case R.id.refresh_menu_item:
				if (refreshView == null) {
					rotation = AnimationUtils.loadAnimation(getApplication(), R.anim.clockwise_refresh);
				    rotation.setRepeatCount(Animation.INFINITE);
				    LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
					refreshView = inflater.inflate(R.layout.actionbar_indeterminate_progress, null);
				}
				refreshView.startAnimation(rotation);
				refreshMenuItem.setActionView(refreshView);
			
		        Intent serviceIntent = new Intent(this, UpdateService.class);
				serviceIntent.putExtra("force_update", true);
				// single channel
				if (menuItem.getMenuInfo() != null) {
					serviceIntent.putExtra("channel", adapter.getCursor().getInt(0));
				}
				startService(serviceIntent);
				break;
		
		case R.id.add_menu_item:
				showDialog(R.id.add_menu_item);
				break;
						
		case R.id.preferences_menu_item:
				Intent prefIntent = new Intent(this, PodcastPreferenceActivity.class);
				startActivity(prefIntent);
				break;
						
		case R.id.mark_listened_all_menu_item:						
		case R.id.mark_listened_older_menu_item:
				if (markListened(menuItem.getItemId(), adapter.getCursor().getInt(0), adapter.getCursor().getInt(4))) {
					requery();
				}
				break;
						
		case R.id.unsubscribe_menu_item:
				AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuItem.getMenuInfo();
				selectedChannel = (info != null) ? new Channel((Cursor)adapter.getItem(info.position)) : null;
				showDialog(R.id.unsubscribe_menu_item);
				break;
				
		case R.id.export_menu_item:
				int exported = PodcastDB.exportOPML(getApplicationContext());
				Toast.makeText(getApplicationContext(), "Exported "+exported+" feeds", Toast.LENGTH_SHORT).show();
				break;
						
		case DOWNLOAD_MENU_ITEM:
				Intent intent = new Intent(this, DownloadService.class);
				intent.setAction(DownloadService.DOWNLOAD);
				ArrayList<String> guids = new ArrayList<String>(1);
				guids.add(adapter.getCursor().getString(0));
				intent.putStringArrayListExtra("guid", guids);
				startService(intent);
				break;
			
		case REMOVE_DOWNLOAD_MENU_ITEM:
				File file = new File(Util.getPodcastFilename(adapter.getCursor().getString(0)));
				file.delete();
				mAdapter.notifyDataSetChanged();
				break;
		
		// Mark this item as listened and cancel any pending downloads of this item
		case MARK_LISTENED_MENU_ITEM:
				markListened(adapter.getCursor().getString(0), adapter.getCursor().getInt(1), true);
				requery();
		case CANCEL_DOWNLOAD_MENU_ITEM:
				Intent cancelIntent = new Intent(this, DownloadService.class);
				cancelIntent.setAction(DownloadService.CANCEL);
				cancelIntent.putExtra("guid", adapter.getCursor().getString(0));
				startService(cancelIntent);
				break;
    	}
		
		return false;
    }
    
    
    
    
    private boolean markListened(int menuItem, int channel_id, int channel_new_items)
	{
		PodcastDB helper = new PodcastDB(getApplicationContext());
		SQLiteDatabase db = helper.getReadableDatabase();
		Calendar cal = Calendar.getInstance();
		long time = System.currentTimeMillis();
		
		// Set time to 1 week ago
		if (menuItem == R.id.mark_listened_older_menu_item) {
			time -= 604800000;
		}
		
		cal.setTimeInMillis(time);
		
		String date = Util.ISO8601_DATE_FORMAT.format(cal.getTime());
		
		String where = "channel_id="+channel_id+" AND pubDate < '"+date+"' AND listened = 0";
		
		ContentValues values = new ContentValues();
    	values.put("listened", 1);
    	
    	int count = db.update(PodcastDB.ITEMS_TABLE, values, where, null);
    	
    	if (count > 0) {
    		
    		values.clear();
    		values.put("new_items", channel_new_items - count);
    		db.update(PodcastDB.CHANNELS_TABLE, values, "_id="+channel_id, null);
    	}
    	
    	helper.close();
    	
    	return (count > 0);
	}
    
    
    
    
    private void markListened(String guid, int channel_id, boolean listened)
	{
		PodcastDB helper = new PodcastDB(getApplicationContext());
    	SQLiteDatabase db = helper.getReadableDatabase();
    	ContentValues values = new ContentValues();
    	
    	values.put("listened", (listened ? 1 : 0));
    	
    	db.update(PodcastDB.ITEMS_TABLE, values, "guid='"+guid+"'", null);
    	
    	values.clear();
    	
    	
    	// Update 'new_items' count for the Channel
    	Cursor cursor = db.query(false, PodcastDB.CHANNELS_TABLE, new String[] {"new_items"},
    			"_id="+channel_id, null, null, null, null, "1");
    	
    	if (cursor.moveToFirst()) {
    		
    		int new_items = cursor.getInt(0);
    		new_items = listened ? new_items - 1 : new_items + 1;
    		values.put("new_items", new_items);
    		db.update(PodcastDB.CHANNELS_TABLE, values, "_id="+channel_id, null);
    	}
    	
    	helper.close();
	}
    
    
    
    
    
    @Override
    public Dialog onCreateDialog(int id, Bundle bundle)
    {
    	if (id == R.id.add_menu_item)
    	{
			LayoutInflater inflater = getLayoutInflater();
            View layout = inflater.inflate(R.layout.new_podcast_dialog, null);
            final EditText urlEditText = (EditText) layout.findViewById(R.id.new_podcast_dialog_input);
            int end = urlEditText.getText().length();
            urlEditText.setSelection(end);
            
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setView(layout);

            builder.setTitle(R.string.new_podcast_dialog_title);
            builder.setCancelable(true);

            builder.setNegativeButton(android.R.string.cancel, null);
            builder.setPositiveButton(android.R.string.ok, new OnClickListener() {
                @Override
				public void onClick(DialogInterface dialog, int arg1) {
                	new AddRefreshPodcastsTask(urlEditText.getText().toString()).execute();
                }
            });

            return builder.create();
    	}
		else if (id == R.id.unsubscribe_menu_item)
    	{
    		AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle("Unsubscribe");
            builder.setMessage("Are you sure you want to unsubscribe from "+selectedChannel.title+"?");
            builder.setCancelable(true);
            builder.setNegativeButton(android.R.string.cancel, null);
            builder.setPositiveButton(android.R.string.ok, new OnClickListener() {
                @Override
				public void onClick(DialogInterface dialog, int arg1) {

                	new Thread(new Runnable() {
                        @Override
						public void run() {
                        	
                        	PodcastDB.deleteChannel(getApplicationContext(), selectedChannel.id);
                        	
                        	selectedChannel = null;
                        	
                        	mUpdateHandler.post(new Runnable() {
								@Override
								public void run() {
									requery();
								}
							});
                        }
                    }).start();
                }
            });

            return builder.create();
    	}
		
		
		return null;
    }
    
    
    
    private void requery()
    {
    	PodcastDB helper = new PodcastDB(getApplicationContext());
		SQLiteDatabase db = helper.getReadableDatabase();

		sAdapter.changeCursor(db.query(false, PodcastDB.CHANNELS_TABLE,
							SubscriptionsAdapter.COLUMNS,
							null, null, null, null, "title", null));
		
		qAdapter.changeCursor(db.query(false, PodcastDB.ITEMS_TABLE,
							QueueAdapter.COLUMNS,
							"listened = 0", null, null, null, "pubDate", null));
		
		helper.close();
    }
    
    
    
    public void buttonClicked(View view)
    {
    	Intent intent = new Intent(MainActivity.this, PlayerActivity.class);
    	startActivity(intent);
    }
    
    
    
    public class PagerActivityDownloadIconTask extends DownloadIconTask
    {    	
    	public PagerActivityDownloadIconTask(int channel_id, ImageView view) {
    		
    		super(PodcastDB.getImageURL(getApplicationContext(), channel_id), view);
    	}
    	
    	@Override
    	public void onPreExecute() {
    		
    		networkAvailable = Util.isNetworkAvailable(MainActivity.this);
    	}
    	
    	@Override
    	protected void onPostExecute(Bitmap bitmap)
    	{    		
    		if (bitmap != null && imageViewReference != null)
    		{
    			imageViewReference.get().setImageBitmap(bitmap);
    		}
    	}
    }
    
    public class AddRefreshPodcastsTask extends AsyncTask<Void, Void, Integer>
    {
    	private ProgressDialog mProgressDialog;
    	private String url;
    	
    	public AddRefreshPodcastsTask(String url) {
    		this.url = url;
    	}
    	
    	@Override
    	protected void onPreExecute()
    	{
    		mProgressDialog = ProgressDialog.show(MainActivity.this,
					"Please wait...", "Adding Podcast...", true);
    	}
    	
    	@Override
    	protected Integer doInBackground(Void... args)
    	{
    		return PodcastDB.addRefresh(getApplicationContext(), url);
    	}
    	
    	@Override
    	protected void onPostExecute(Integer updated)
    	{
    		if (updated > 0)
    		{
    			mProgressDialog.dismiss();
				requery();
    		}
    	}

    }
    
}
